package z_mxsTest.testCleanComment;

import javax.swing.*;
import java.awt.*;
//import java.awt.event.ActionEvent;
//import java.awt.event.ActionListener;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * Java文件注释清理工具（非正则版）
 * 采用字符扫描方式处理，彻底解决正则递归导致的StackOverflowError
 */
public class JavaCommentCleaner extends JFrame {
    private static final long serialVersionUID = 1L;
    
    private JTextField dirPathField;
    private JTextArea logArea;
    private File selectedDir;

    public JavaCommentCleaner() {
        initUI();
    }

    /**
     * 初始化UI界面
     */
    private void initUI() {
        setTitle("Java文件注释清理工具（非正则版）");
        setSize(850, 650);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setLayout(new BorderLayout(15, 15));

        // 内容面板添加边框
        Container contentPane = getContentPane();
        if (contentPane instanceof JComponent) {
            ((JComponent) contentPane).setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
        }

        // 顶部：目录选择区域
        JPanel topPanel = new JPanel(new BorderLayout(10, 10));
        JLabel dirLabel = new JLabel("目标目录：", JLabel.RIGHT);
        dirLabel.setPreferredSize(new Dimension(80, 30));
        dirPathField = new JTextField();
        dirPathField.setEditable(false);
        dirPathField.setFont(new Font("Microsoft YaHei", Font.PLAIN, 12));
        JButton selectDirBtn = new JButton("浏览");
        selectDirBtn.setPreferredSize(new Dimension(80, 30));

        selectDirBtn.addActionListener(e -> {
            JFileChooser chooser = new JFileChooser();
            chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
            chooser.setDialogTitle("选择Java文件所在目录");
            int result = chooser.showOpenDialog(JavaCommentCleaner.this);
            if (result == JFileChooser.APPROVE_OPTION) {
                selectedDir = chooser.getSelectedFile();
                dirPathField.setText(selectedDir.getAbsolutePath());
            }
        });

        topPanel.add(dirLabel, BorderLayout.WEST);
        topPanel.add(dirPathField, BorderLayout.CENTER);
        topPanel.add(selectDirBtn, BorderLayout.EAST);
        add(topPanel, BorderLayout.NORTH);

        // 中间：日志显示区域
        JPanel logPanel = new JPanel(new BorderLayout(10, 10));
        JLabel logLabel = new JLabel("处理日志：");
        logLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 12));
        logArea = new JTextArea();
        logArea.setEditable(false);
        logArea.setFont(new Font("Monaco", Font.PLAIN, 12));
        logArea.setLineWrap(false);
        logArea.setWrapStyleWord(false);
        JScrollPane logScroll = new JScrollPane(logArea);
        logScroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        logScroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);

        logPanel.add(logLabel, BorderLayout.NORTH);
        logPanel.add(logScroll, BorderLayout.CENTER);
        add(logPanel, BorderLayout.CENTER);

        // 底部：操作按钮区域
        JPanel btnPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 30, 15));
        JButton startBtn = new JButton("开始清理（安全模式）");
        JButton clearBtn = new JButton("清空日志");
        Dimension btnSize = new Dimension(180, 40);
        Font btnFont = new Font("Microsoft YaHei", Font.BOLD, 12);
        startBtn.setPreferredSize(btnSize);
        clearBtn.setPreferredSize(btnSize);
        startBtn.setFont(btnFont);
        clearBtn.setFont(btnFont);

        startBtn.addActionListener(e -> {
            if (selectedDir == null || !selectedDir.exists()) {
                JOptionPane.showMessageDialog(JavaCommentCleaner.this,
                        "请选择有效的目录！", "错误提示", 
                        JOptionPane.ERROR_MESSAGE);
                return;
            }
            
            new Thread(() -> {
                log("=== 开始安全清理 | 目标目录：" + selectedDir.getAbsolutePath() + " ===");
                try {
                    int total = countJavaFiles(selectedDir);
                    log("扫描完成 | 共发现 " + total + " 个Java文件");
                    if (total == 0) {
                        log("提示：目录下未找到Java文件，无需处理");
                        return;
                    }
                    int success = processJavaFiles(selectedDir);
                    log("=== 清理完成 | 成功处理 " + success + " 个文件 | 失败 " + (total - success) + " 个文件 ===");
                } catch (Exception ex) {
                    log("处理异常：" + ex.getMessage());
                    ex.printStackTrace();
                }
            }).start();
        });

        clearBtn.addActionListener(e -> logArea.setText(""));

        btnPanel.add(startBtn);
        btnPanel.add(clearBtn);
        add(btnPanel, BorderLayout.SOUTH);
    }

    /**
     * 递归统计目录下所有Java文件数量
     */
    private int countJavaFiles(File dir) {
        if (dir == null || !dir.isDirectory()) {
            return 0;
        }
        int count = 0;
        File[] files = dir.listFiles();
        if (files == null) {
            log("警告：无权限访问目录 " + dir.getAbsolutePath());
            return 0;
        }
        for (File file : files) {
            if (file.isDirectory()) {
                count += countJavaFiles(file);
            } else if (file.getName().toLowerCase().endsWith(".java")) {
                count++;
            }
        }
        return count;
    }

    /**
     * 递归处理目录下所有Java文件
     */
    private int processJavaFiles(File dir) throws IOException {
        if (dir == null || !dir.isDirectory()) {
            return 0;
        }
        int success = 0;
        File[] files = dir.listFiles();
        if (files == null) {
            log("警告：无权限访问目录 " + dir.getAbsolutePath() + "，跳过该目录");
            return 0;
        }
        for (File file : files) {
            if (file.isDirectory()) {
                success += processJavaFiles(file);
            } else if (file.getName().toLowerCase().endsWith(".java")) {
                if (cleanCommentSafely(file)) {
                    success++;
                    log("成功：" + file.getAbsolutePath());
                } else {
                    log("失败：" + file.getAbsolutePath());
                }
            }
        }
        return success;
    }

    /**
     * 核心方法：使用字符扫描方式清理注释
     * 完全不使用正则表达式，避免递归栈溢出
     */
    private boolean cleanCommentSafely(File javaFile) throws IOException {
        // 1. 读取文件内容为字符列表（保留原始格式）
        List<Character> charList = new ArrayList<>();
        try (BufferedReader br = new BufferedReader(
                new InputStreamReader(new FileInputStream(javaFile), StandardCharsets.UTF_8))) {
            int c;
            while ((c = br.read()) != -1) {
                charList.add((char) c);
            }
        }

        // 2. 扫描并标记需要删除的注释位置
        boolean[] deleteFlags = new boolean[charList.size()];
        int length = charList.size();
        int i = 0;
        
        // 状态标记
        boolean inString = false;       // 是否在字符串中
        boolean inChar = false;         // 是否在字符中
        //char stringDelimiter = '"';     // 字符串分隔符（"或'）
        boolean escapeNext = false;     // 下一个字符是否被转义

        while (i < length) {
            char current = charList.get(i);
            
            // 处理转义字符
            if (escapeNext) {
                escapeNext = false;
                i++;
                continue;
            }
            
            // 处理双引号字符串
            if (current == '"' && !inChar) {
                inString = !inString;
                if (inString) {
                    //stringDelimiter = '"';
                }
                i++;
                continue;
            }
            
            // 处理单引号字符
            if (current == '\'' && !inString) {
                inChar = !inChar;
                if (inChar) {
                    //stringDelimiter = '\'';
                }
                i++;
                continue;
            }
            
            // 转义字符处理
            if (current == '\\' && (inString || inChar)) {
                escapeNext = true;
                i++;
                continue;
            }
            
            // 如果在字符串或字符中，不处理注释
            if (inString || inChar) {
                i++;
                continue;
            }
            
            // 处理单行注释 //
            if (current == '/' && i + 1 < length && charList.get(i + 1) == '/') {
                // 标记从当前位置到行尾的字符为待删除
                //int start = i;
                while (i < length && charList.get(i) != '\n') {
                    deleteFlags[i] = true;
                    i++;
                }
                // 保留换行符
                if (i < length && charList.get(i) == '\n') {
                    i++;
                }
                continue;
            }
            
            // 处理多行注释 /* */
            if (current == '/' && i + 1 < length && charList.get(i + 1) == '*') {
                // 标记从/*开始到*/结束的字符为待删除
                deleteFlags[i] = true;  // 标记 '/'
                deleteFlags[i + 1] = true;  // 标记 '*'
                i += 2;
                
                while (i < length) {
                    if (charList.get(i) == '*' && i + 1 < length && charList.get(i + 1) == '/') {
                        deleteFlags[i] = true;  // 标记 '*'
                        deleteFlags[i + 1] = true;  // 标记 '/'
                        i += 2;
                        break;
                    }
                    deleteFlags[i] = true;
                    i++;
                }
                continue;
            }
            
            // 其他字符不处理
            i++;
        }

        // 3. 构建清理后的内容
        StringBuilder cleanedContent = new StringBuilder();
        for (i = 0; i < length; i++) {
            if (!deleteFlags[i]) {
                cleanedContent.append(charList.get(i));
            }
        }

        // 4. 仅当内容有变化时写入文件
        //String originalContent = new String(cleanedContent);
        try (BufferedReader br = new BufferedReader(
                new InputStreamReader(new FileInputStream(javaFile), StandardCharsets.UTF_8))) {
            StringBuilder original = new StringBuilder();
            int c;
            while ((c = br.read()) != -1) {
                original.append((char) c);
            }
            
            if (!cleanedContent.toString().equals(original.toString())) {
                try (BufferedWriter bw = new BufferedWriter(
                        new OutputStreamWriter(new FileOutputStream(javaFile), StandardCharsets.UTF_8))) {
                    bw.write(cleanedContent.toString());
                }
            }
        }

        return true;
    }

    /**
     * 线程安全的日志输出
     */
    private void log(String message) {
        SwingUtilities.invokeLater(() -> {
            logArea.append(message + System.lineSeparator());
            logArea.setCaretPosition(logArea.getDocument().getLength());
        });
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new JavaCommentCleaner().setVisible(true));
    }
}
